<?php
/**
 * <pre>
 * <b>RUBIK IT Solution & Development ltd.</b>
 *
 * PROJECT      : rubik-base
 * COPYRIGHT    : 2008
 * ------------------------------------------------------
 * 
 * AbstractRubikDBFinder.class.php
 * 
 * File for defining class AbstractRubikDBFinder
 * </pre>
 * 
 * Created on	: May 5, 2008
 * 
 * @version 		1.5.1
 * @author			Dang Nhon Hoa <HoaDN@rubik.com.vn>
 * @access			public
 * @package			rubik.base.dbo
 *
 */

RCoreImporter::cls("dbo.AbstractRubikDBObject" );

/**
 * This class help create the WHERE clause in SQL statement.
 * <pre>
 * 		Example for sub class:
 * 
 * </pre>
 */
class AbstractRubikDBFinder extends AbstractRubikDBObject {
	
	var $_selectFrom = null;
	
	/**
	 * Object constructor to set table and key field
	 *
	 * Can be overloaded/supplemented by the child class
	 *
	 * @access protected
	 * 
	 * @param AbstractRubikDTO / string $selectFrom This can be an AbstractRubikDTO or a Select From string
	 * @param string $extCondition
	 * @param string $orderBy
	 * @param Database $db database object of this DB Info.
	 */
	function __construct($selectFrom = "", $extCondition = "", $orderBy = "", $db = null) {
		parent::__construct ( "", "", $orderBy, $db );
		
		if (is_object ( $selectFrom )) {
			$this->setSelectFromDTO ( $selectFrom );
			if (! empty ( $this->_where )) {
				$this->_where .= " AND ";
			}
			$this->_where .= $extCondition;
		} else {
			$this->_selectFrom = $selectFrom;
			$this->_where = $extCondition;
		}
	}
	
	/**
	 * Set the select clause from a DTO
	 *
	 * @param AbstractRubikDTO $rubikDTO
	 */
	function setSelectFromDTO($rubikDTO) {
		if (is_string ( $rubikDTO )) {
			$rubikDTO = new $rubikDTO ( );
		}
		
		$selectDbInfo = RubikDBFactory::getDBInfo ( $rubikDTO );
		$dbInfo = &RubikDBFactory::getDBInfo ( $this );
		
		$dbInfo->setFromClause ( $selectDbInfo->getFromClause () );
		$dbInfo->setSelectClause ( $selectDbInfo->getSelectClause () );
		$this->_selectFrom = $selectDbInfo->getSelectSQL ();
		
		$extCon = strtoupper ( $rubikDTO->getWhereClause () );
		$start = strpos ( $extCon, "WHERE " );
		if ($start !== false) {
			$start += 6;
			$this->_where = substr ( $selectDbInfo->getWhereClause (), $start );
		}
	}
	
	/**
	 * Create where class
	 * CAUTION: this function can be overide by subclass if neccesary
	 *
	 * @param string $where the where clause after generated.
	 * @return string the where clause after doing some more process.
	 */
	function _createWhere($where) {
		$extCondition = $this->_where;
		
		if (empty ( $where )) {
			if (empty ( $extCondition )) {
				return;
			} else {
				return " WHERE " . $extCondition;
			}
		}
		
		if (empty ( $extCondition )) {
			return $where;
		}
		return $where . " AND (" . $extCondition . ")";
	}
	
	/**
	 * get where clause with the current criteria object
	 * 
	 * Can be overloaded/supplemented by the child class
	 * 
	 * @param string $combileCondition (AND/OR) the TEXT to combine 2 condition. Default: "AND"
	 * @param boolean $ignoreNull	where clause will created with the null value if $ignoreNull = false
	 * @param string $compareKey the key for compare. Ex: "like", "=", ">",...
	 * @param string $prefix the prefix of like clause Ex: "%"
	 * @param string $subfix the subfix of like clause Ex: "*"
	 *  
	 * @return WHERE clause
	 */
	function getWhereClause($combineCondition = "AND", $ignoreNull = true, $compareKey = "like", $prefix = "", $subfix = "") {
		return $this->_createWhere ( $this->createWhereClause ( $combineCondition, $ignoreNull, $compareKey, $prefix, $subfix ) );
	}
	
	/**
	 * get where clause with the current criteria object
	 * 
	 * Can be overloaded/supplemented by the child class
	 * 
	 * @param string $combileCondition (AND/OR) the TEXT to combine 2 condition. Default: "AND"
	 * @param boolean $ignoreNull	where clause will created with the null value if $ignoreNull = false
	 * 
	 * @return WHERE clause
	 */
	function getWhereClauseWithAnyText($combineCondition = "AND", $ignoreNull = true) {
		return $this->_createWhere ( $this->createWhereClause ( $combineCondition, $ignoreNull, "like", "%", "%" ) );
	}
	
	/**
	 * Get the select SQL of this finder
	 *
	 * @param string $combileCondition (AND/OR) the TEXT to combine 2 condition. Default: "AND"
	 * @param boolean $ignoreNull	where clause will created with the null value if $ignoreNull = false
	 * @param string $compareKey the key for compare. Ex: "like", "=", ">",...
	 * @param string $prefix the prefix of like clause Ex: "%"
	 * @param string $subfix the subfix of like clause Ex: "*"
	 * 
	 * @return string "SELECT u.*, g.group_name FROM u.group_id = g.group_id WHERE g.group_name='admin'"
	 */
	function getSelectSQL($combineCondition = "AND", $ignoreNull = true, $compareKey = "like", $prefix = "", $subfix = "") {
		$where = "\n" . $this->getWhereClause ( $combineCondition, $ignoreNull, $compareKey, $prefix, $subfix );
		$result = $this->_selectFrom . $where;
		$orderBy = $this->getOrderBy ();
		if (! empty ( $orderBy )) {
			$result .= "\n" . $orderBy;
		}
		return $result;
	}
	
	/**
	 * get the select clause with search clause corresponding to any
	 *
	 * @param string $combileCondition (AND/OR) the TEXT to combine 2 condition. Default: "AND"
	 * @param boolean $ignoreNull	where clause will created with the null value if $ignoreNull = false
	 * @param string $prefixSubFix the prefix and subfix of like clause
	 * @return string "SELECT u.*, g.group_name FROM u.group_id = g.group_id WHERE g.group_name='%admin%'"
	 */
	function getSelectSQLWithAny($combineCondition = "AND", $ignoreNull = true) {
		$result = $this->_selectFrom;
		$result .= "\n" . $this->getWhereClauseWithAnyText ( $combineCondition, $ignoreNull );
		$orderBy = $this->getOrderBy ();
		if (! empty ( $orderBy )) {
			$result .= "\n" . $orderBy;
		}
		return $result;
	}

	/**
	 * Get where clause with the current criteria object
	 * 
	 * @param string $combileCondition (AND/OR) the TEXT to combine 2 condition. Default: "AND"
	 * @param boolean $ignoreNull	where clause will created with the null value if $ignoreNull = false
	 * @param string $compareKey the key for compare. Ex: "like", "=", ">",...
	 * @param string $prefix the prefix of like clause Ex: "%"
	 * @param string $subfix the subfix of like clause Ex: "*"
	 * 
	 * @return WHERE clause
	 */
	function createWhereClause($combineCondition = "AND", $ignoreNull=true, $compareKey = "like", $prefix = "", $subfix = "") {
		$this->prepareData ();
		$compareKey = strtoupper($compareKey);
		
		$fmtsql = " WHERE %s";
		$dbInfo = RubikDBFactory::getDBInfo($this);
		$fieldList = $dbInfo->getFieldList($this, $ignoreNull, true);
		
		$compareKey = strtoupper($compareKey);
		foreach ($fieldList as $dbField) 
		{
			$fieldName = $dbField->fieldName;
			$val = $this->$fieldName;
			
			$clause = $this->_createFieldCondition($compareKey, $val, $fieldName, $prefix, $subfix, $dbField, $dbInfo);
			
			if ($clause) {
				$tmp[] = $clause;
			}
		}
		$result = empty($tmp) ? '' : sprintf( $fmtsql, implode( " $combineCondition ", $tmp ));
		return $result;
	}

	/**
	 * Function for crreating the condition of a field.
	 * NOTE: this funciton should be override in specical treat.
	 *
	 * @param string $compareKey the comparekey such as "=" or ">" or "<" or ">="
	 * @param mix $val
	 * @param string $fieldName
	 * @param string $prefix
	 * @param string $subfix
	 * @param RubikDBField $dbField
	 * @param RubikDBInfo  $dbInfo
	 * @return string ex: `u`.`join_date` >= '2008-12-15' AND `u`.`join_date` < '2009-12-15'  
	 */
	function _createFieldCondition($compareKey, $val, $fieldName, $prefix, $subfix, &$dbField, &$dbInfo) {
			// special treat for SYM_TYPE_TIME_NUMBER
			if ($dbField->dataType == SYM_TYPE_TIME_NUMBER & $compareKey == 'LIKE') {
				//TODO for now we just care about date not time
				$db = $dbInfo->getDatabase();
				$format = $db->getFormatDateTime(SYM_TYPE_DATE);
				$val = date($format, $val);
				$val = $prefix.$val.$subfix;
				$val = $dbInfo->dbQuoteData($val);
				return "FROM_UNIXTIME(".$dbField->getNameWithAlias($dbInfo).") $compareKey $val";
			}
			
			if (!RStringHelper::isEmpty($prefix) || !RStringHelper::isEmpty($subfix)) {
				$val = $prefix.$val.$subfix;
			}
			
			if ($val === null) {
				$val = 'NULL';
				$compareKey = "IS";
			}
			else {
				$val = $dbInfo->dbQuoteData($val);
			}
			
			return $dbField->getNameWithAlias($dbInfo)." $compareKey $val";
	}
	
	/**
	 * OVERRIDE
	 * Get the SELECT count(*) of this DBO
	 *
	 * @return string ex: SELECT count(*) FROM user u JOIN user_group g ON u.group_id = g.group_id
	 */
	function getSelectCountSQL() {
		$dbInfo = RubikDBFactory::getDBInfo($this);
		$sql = "SELECT count(*) ";
		$sql .= "\n FROM ( "; // Fix the problem when the SELECT have group by
		$sql .= "\n			".$this->getSelectSQL();
		$sql .= "\n		) _count";
		return $sql;
	}
	
	/**
	 * Function for added addtion from clause in run time and avoid added serveral times.
	 * This function normally used in overided of function _createFieldCondition
	 * 
	 * @param $key the indentify text for avoid duplicate
	 * @param $addedClause the added clause after the current FROM clause
	 * @return boolean
	 */
	function _addToFromClause($key, $addedClause) {
		static $arrKeys;
		if (empty($arrKeys)) {
			$arrKeys = array();
		}
		
		if (!$arrKeys[$key]) {
			$this->_selectFrom .= $addedClause;
			$arrKeys[$key] = true;
			return true;
		}
		return false;
	}
}
?>